package com.cby.library.common.network.converter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;

/**
 * String转换器
 *
 * @author 徐智伟
 * @create 16/2/3
 */
public class StringConverterFactory extends Converter.Factory {
  static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");

  static final String CHARSET_UTF8 = "utf-8";

  private String sCharSet;

  public StringConverterFactory(String charSet) {
    sCharSet = charSet;
  }

  public static StringConverterFactory create() {
    return new StringConverterFactory(CHARSET_UTF8);
  }

  public static StringConverterFactory create(String charSet) {
    return new StringConverterFactory(charSet);
  }

  private static String convertUnicode(String ori) {
    char aChar;
    int len = ori.length();
    StringBuffer outBuffer = new StringBuffer(len);
    for (int x = 0; x < len; ) {
      aChar = ori.charAt(x++);
      if (aChar == '\\') {
        aChar = ori.charAt(x++);
        if (aChar == 'u') {
          // Read the xxxx
          int value = 0;
          int cLen = 4;
          for (int i = 0; i < cLen; i++) {
            aChar = ori.charAt(x++);
            switch (aChar) {
              case '0':
              case '1':
              case '2':
              case '3':
              case '4':
              case '5':
              case '6':
              case '7':
              case '8':
              case '9':
                value = (value << 4) + aChar - '0';
                break;
              case 'a':
              case 'b':
              case 'c':
              case 'd':
              case 'e':
              case 'f':
                value = (value << 4) + 10 + aChar - 'a';
                break;
              case 'A':
              case 'B':
              case 'C':
              case 'D':
              case 'E':
              case 'F':
                value = (value << 4) + 10 + aChar - 'A';
                break;
              default:
                throw new IllegalArgumentException("Malformed   \\uxxxx   encoding.");
            }
          }
          outBuffer.append((char) value);
        } else {
          if (aChar == 't') {
            aChar = '\t';
          } else if (aChar == 'r') {
            aChar = '\r';
          } else if (aChar == 'n') {
            aChar = '\n';
          } else if (aChar == 'f') {
            aChar = '\f';
          }
          outBuffer.append(aChar);
        }
      } else {
        outBuffer.append(aChar);
      }
    }
    return outBuffer.toString();
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    if (String.class.equals(type)) {
      return new ResponseBodyConverter();
    }
    return null;
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    if (String.class.equals(type)) {
      return new Converter<String, RequestBody>() {
        @Override
        public RequestBody convert(String value) throws IOException {

          return RequestBody.create(MEDIA_TYPE, value);
        }
      };
    }
    return null;
  }

  private final class ResponseBodyConverter implements Converter<ResponseBody, String> {
    @Override
    public String convert(ResponseBody value) throws IOException {
      BufferedReader r = new BufferedReader(new InputStreamReader(value.byteStream(), sCharSet));
      StringBuilder total = new StringBuilder();
      String line;
      while ((line = r.readLine()) != null) {
        total.append(line);
      }
      if (r != null) {
        r.close();
      }
      return convertUnicode(total.toString());
    }
  }
}